package com.nervenets.web.redis;

import com.google.gson.Gson;
import com.nervenets.utils.StringUtils;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * Created by Joe on 2017/12/16.
 */
@Component
public class RedisSetDao {
    @Resource
    private RedisTemplate redisTemplate;

    private static boolean assertNull(String string) {
        return StringUtils.isEmpty(string)
                || "NIL".equals(string.toUpperCase())
                || "NULL".equals(string.toUpperCase());
    }

    private static String toJson(RedisDomain domain) {
        return new Gson().toJson(domain);
    }

    public void saveOrUpdate(RedisSetDomain domain) {
        redisTemplate.execute((RedisCallback) rc -> {
            final Boolean result = rc.hSet(domain.getRedisKey().getBytes(), domain.getField().getBytes(), toJson(domain).getBytes());
            if (result && domain.getExpire() > 0) {
                rc.expire(domain.getRedisKey().getBytes(), domain.getExpire());
            }
            return result;
        });
    }

    public void saveOrUpdate(RedisSetDomain... domain) {
        for (RedisSetDomain redisSetDomain : domain) {
            saveOrUpdate(redisSetDomain);
        }
    }

    public boolean exists(RedisSetDomain domain) {
        return (boolean) redisTemplate.execute((RedisCallback) rc -> rc.hExists(domain.getRedisKey().getBytes(), domain.getField().getBytes()));
    }

    public <T extends RedisSetDomain> T getRedisSetDomain(T domain) {
        return (T) redisTemplate.execute((RedisCallback) rc -> {
            final byte[] bytes = rc.hGet(domain.getRedisKey().getBytes(), domain.getField().getBytes());
            String json = new String(bytes);
            if (assertNull(json)) {
                return null;
            }
            return (T) new Gson().fromJson(json, domain.getClass());
        });
    }

    public <T extends RedisSetDomain> void delete(T domain) {
        redisTemplate.execute((RedisCallback) rc -> rc.hDel(domain.getRedisKey().getBytes(), domain.getField().getBytes()));
    }

    public void incrBy(RedisOrderedSetDomain domain, int offset) {
        redisTemplate.execute((RedisCallback) rc -> rc.hIncrBy(domain.getRedisKey().getBytes(), domain.getField().getBytes(), offset));
    }

    public void incr(RedisOrderedSetDomain domain) {
        redisTemplate.execute((RedisCallback) rc -> rc.hIncrBy(domain.getRedisKey().getBytes(), domain.getField().getBytes(), 1));
    }
}
